package util

import (
	"card/constant"
	"context"
	"crypto/rand"
	"fmt"
	"github.com/duke-git/lancet/v2/strutil"
	"github.com/spf13/cast"
	"golang.org/x/crypto/bcrypt"
	"io"
	mathrand "math/rand"
	"os"
	"reflect"
	"sort"
	"strings"
	"time"
)

func MicrosecondsStr(elapsed time.Duration) string {
	return fmt.Sprintf("%.3fms", float64(elapsed.Nanoseconds())/1e6)
}

// RandomNumber 生成长度为 length 随机数字字符串
func RandomNumber(length int) string {
	table := [...]byte{'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'}
	b := make([]byte, length)
	n, err := io.ReadAtLeast(rand.Reader, b, length)
	if n != length {
		panic(any(err))
	}
	for i := 0; i < len(b); i++ {
		b[i] = table[int(b[i])%len(table)]
	}
	return string(b)
}
func FileExist(path string) bool {
	_, err := os.Stat(path)
	if err != nil {
		if os.IsNotExist(err) {
			return false
		}
	}
	return true
}

func GenLogId() string {
	now := time.Now()
	logId := ((now.Unix()*100000 + int64(now.Nanosecond()/1000)) & 0x7FFFFFFF) | 0x80000000
	return cast.ToString(logId)
}
func GetLogId(ctx context.Context) string {
	if ctx == nil {
		return ""
	}
	logId, ok := ctx.Value(constant.LogId).(string)
	if ok {
		return logId
	}
	return ""
}

func Parse(value string) interface{} {
	var conf = make(map[string]string)
	arr := strings.Split(strings.Trim(value, "\r\n"), "\r\n")
	if strings.Contains(value, ":") {
		for _, v := range arr {
			list := strings.Split(v, ":")
			conf[list[0]] = list[1]
		}
		return conf
	} else {
		return arr
	}
}

func Empty(val interface{}) bool {
	if val == nil {
		return true
	}
	v := reflect.ValueOf(val)
	switch v.Kind() {
	case reflect.String, reflect.Array:
		return v.Len() == 0
	case reflect.Map, reflect.Slice:
		return v.Len() == 0 || v.IsNil()
	case reflect.Bool:
		return !v.Bool()
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return v.Int() == 0
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return v.Uint() == 0
	case reflect.Float32, reflect.Float64:
		return v.Float() == 0
	case reflect.Interface, reflect.Ptr:
		return v.IsNil()
	}
	return reflect.DeepEqual(val, reflect.Zero(v.Type()).Interface())
}

// RandomString 生成长度为 length 的随机字符串
func RandomString(length int) string {
	mathrand.Seed(time.Now().UnixNano())
	letters := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
	b := make([]byte, length)
	for i := range b {
		b[i] = letters[mathrand.Intn(len(letters))]
	}
	return string(b)
}

// BcryptHash 使用 bcrypt 对密码进行加密
func BcryptHash(password string) string {
	// GenerateFromPassword 的第二个参数是 cost 值。建议大于 12，数值越大耗费时间越长
	bytes, _ := bcrypt.GenerateFromPassword([]byte(password), 10)
	return string(bytes)
}

// BcryptCheck 对比明文密码和数据库的哈希值
func BcryptCheck(password, hash string) bool {
	err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
	return err == nil
}

// BcryptIsHashed 判断字符串是否是哈希过的数据
func BcryptIsHashed(str string) bool {
	// bcrypt 加密后的长度等于 60
	return len(str) == 60
}

func ArrayPop[T any](slice []T) ([]T, T) {
	var item T
	item = slice[0]
	slice = slice[1:]
	return slice, item
}

func SliceSubstring2Int(arr []string, offset int) []int {
	replace := make([]int, len(arr))
	for i := 0; i < len(arr); i++ {
		s := arr[i]
		replace[i] = cast.ToInt(strutil.Substring(s, offset, uint(len(s))))
	}
	sort.Ints(replace)
	return replace
}

func CheckHasJoker(arr []string) bool {
	for i := 0; i < len(arr); i++ {
		str := arr[0]
		if str[0] == 'e' {
			return true
		}
	}
	return false
}

func GetCountNumber(arr []int, number int) []int {
	data := make(map[int]int)
	for _, v := range arr {
		data[cast.ToInt(v)] = data[cast.ToInt(v)] + 1
	}
	val, ok := data[number]
	slice := make([]int, number)
	if ok {
		for i := 0; i < number; i++ {
			slice[i] = val
		}
	}
	return slice
}
